package com.xbongbong.paas.util;

import com.xbongbong.paas.constant.ExcelConstant;
import com.xbongbong.paas.exception.ExcelAnalysisException;
import com.xbongbong.paas.exception.ExcelTitleCheckException;
import com.xbongbong.paas.help.ImportRedisHelper;
import com.xbongbong.paas.help.ImportSendHelper;
import com.xbongbong.paas.pojo.FieldAttrEntityForImport;
import com.xbongbong.paas.pojo.dto.ImportFormDataDTO;
import com.xbongbong.paas.redis.PaasRedisHelper;
import com.xbongbong.paas.service.HandleImportService;
import com.xbongbong.paas.toolbox.exception.XbbException;
import com.xbongbong.pro.enums.errorcodes.ImportErrorCodeEnum;
import com.xbongbong.pro.enums.errorcodes.SystemErrorCodeEnum;
import com.xbongbong.saas.service.toolbox.help.PackageStatusHelp;
import org.apache.poi.ooxml.util.SAXHelper;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.openxml4j.opc.OPCPackage;
import org.apache.poi.openxml4j.opc.PackageAccess;
import org.apache.poi.xssf.eventusermodel.ReadOnlySharedStringsTable;
import org.apache.poi.xssf.eventusermodel.XSSFReader;
import org.apache.poi.xssf.model.StylesTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xml.sax.ContentHandler;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import javax.xml.parsers.ParserConfigurationException;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * 处理Excel07版及以上的读取
 *
 * @author 魏荣杰
 * @date 2019/11/20 11:53 下午
 * @since v4.6.0
 * @version v4.6.0
 */
public class ExcelXlsxReader {
    private static final Logger LOG = LoggerFactory.getLogger(ExcelXlsxReader.class);

    private OPCPackage opcPackage;
    private ExcelXlsxSheetContentsHandler excelXlsxSheetContentsHandler;
    private ExcelReadDataDelegated excelReadDataDelegated;
    /**
     * 表格索引值
     */
    private int sheetIndex = 0;
    /**
     * 表格名称
     */
    private String sheetName;
    /**
     * 数据开始的行数
     */
    private int startRowIndex = -1;
    /**
     * 解释
     */
    private List<FieldAttrEntityForImport> fieldAttrEntityList;
    private ImportFormDataDTO importFormDataDTO;
    private ImportSendHelper importSendHelper;
    private HandleImportService handleImportService;
    private PaasRedisHelper paasRedisHelper;
    private ImportRedisHelper importRedisHelper;
    private PackageStatusHelp packageStatusHelp;

    public ExcelXlsxReader(String filePath, ExcelReadDataDelegated excelReadDataDelegated) throws InvalidFormatException {
        this.opcPackage = OPCPackage.open(filePath, PackageAccess.READ);
        this.excelReadDataDelegated = excelReadDataDelegated;
    }

    public ExcelXlsxReader(InputStream inputStream, ExcelReadDataDelegated excelReadDataDelegated) throws IOException, InvalidFormatException {
        this.opcPackage = OPCPackage.open(inputStream);
        this.excelReadDataDelegated = excelReadDataDelegated;
    }

    public ExcelXlsxReader(String filePath, ExcelReadDataDelegated excelReadDataDelegated, int startRowIndex, List<FieldAttrEntityForImport> fieldAttrEntityList, ImportFormDataDTO importFormDataDTO) throws IOException, InvalidFormatException {
        this.opcPackage = OPCPackage.open(filePath, PackageAccess.READ);
        this.excelReadDataDelegated = excelReadDataDelegated;
        this.startRowIndex = startRowIndex;
        this.fieldAttrEntityList = fieldAttrEntityList;
        this.importFormDataDTO = importFormDataDTO;
    }

    public ExcelXlsxReader(InputStream inputStream, ExcelReadDataDelegated excelReadDataDelegated, int startRowIndex, List<FieldAttrEntityForImport> fieldAttrEntityList, ImportFormDataDTO importFormDataDTO, ImportSendHelper importSendHelper, HandleImportService handleImportService, PaasRedisHelper paasRedisHelper, ImportRedisHelper importRedisHelper, PackageStatusHelp packageStatusHelp) throws IOException, InvalidFormatException {
        this.opcPackage = OPCPackage.open(inputStream);
        this.excelReadDataDelegated = excelReadDataDelegated;
        this.startRowIndex = startRowIndex;
        this.fieldAttrEntityList = fieldAttrEntityList;
        this.importFormDataDTO = importFormDataDTO;
        this.importSendHelper = importSendHelper;
        this.handleImportService = handleImportService;
        this.paasRedisHelper = paasRedisHelper;
        this.importRedisHelper = importRedisHelper;
        this.packageStatusHelp = packageStatusHelp;
    }

    /**
     * Description: 读取Excel
     * @author 魏荣杰
     * @date 2019/11/21 2:01 下午
     * @since v4.6.0
     */
    public void read() throws XbbException {
        InputStream inputStream = null;
        try {
            XSSFReader xssfReader = new XSSFReader(opcPackage);
            StylesTable stylesTable = xssfReader.getStylesTable();
            ReadOnlySharedStringsTable readOnlySharedStringsTable = new ReadOnlySharedStringsTable(opcPackage);

            XSSFReader.SheetIterator sheetIterator = (XSSFReader.SheetIterator) xssfReader.getSheetsData();
            while (sheetIterator.hasNext()) {
                sheetIndex++;
                inputStream = sheetIterator.next();
                sheetName = sheetIterator.getSheetName();
                // 过滤单元格下拉框的处理
                if (sheetName.contains(ExcelConstant.HIDDEN_SHEET)) {
                    continue;
                }
                this.excelXlsxSheetContentsHandler = new ExcelXlsxSheetContentsHandler(excelReadDataDelegated, startRowIndex, fieldAttrEntityList, importFormDataDTO, sheetName, sheetIndex, importSendHelper, handleImportService, importRedisHelper, paasRedisHelper, packageStatusHelp);
                parseSheetXml(stylesTable, readOnlySharedStringsTable, inputStream);
                break;
            }

        } catch (ExcelAnalysisException e) {
            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235000.getCode(), e.getMessage());
        } catch (ExcelTitleCheckException e) {
            LOG.error("com.xbongbong.paas.util.ExcelXlsxReader.read error: ", e);
            throw new XbbException(ImportErrorCodeEnum.API_ERROR_235002, e.getMessage());
        } catch (Exception e) {
            LOG.error("com.xbongbong.paas.util.ExcelXlsxReader.read error: ", e);
            throw new XbbException(SystemErrorCodeEnum.API_ERROR_100001);
        } finally {
            if (inputStream != null) {
                try {
                    inputStream.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.paas.util.ExcelXlsxReader.read inputStream close error: ", e);
                }
            }
            if (opcPackage != null) {
                try {
                    opcPackage.close();
                } catch (IOException e) {
                    LOG.error("com.xbongbong.paas.util.ExcelXlsxReader.read opcPackage close error: ", e);
                }
            }
        }
    }

    /**
     * Description: 读取sheet数据
     * @param styles
     * @param readOnlySharedStringsTable
     * @param inputStream
     * @author 魏荣杰
     * @date 2019/11/21 1:59 下午
     * @since v4.6.0
     */
    private void parseSheetXml(StylesTable styles, ReadOnlySharedStringsTable readOnlySharedStringsTable, InputStream inputStream) throws ParserConfigurationException, SAXException, IOException {
        ExcelImportDataFormatter formatter = new ExcelImportDataFormatter();
        InputSource sheetSource = new InputSource(inputStream);
        XMLReader sheetParser = SAXHelper.newXMLReader();
        ContentHandler handler = new ExcelXlsxSheetXMLHandler(styles, null, readOnlySharedStringsTable, excelXlsxSheetContentsHandler, formatter, false, excelXlsxSheetContentsHandler);
        sheetParser.setContentHandler(handler);
        sheetParser.parse(sheetSource);
    }
}
